#region Imported Namespaces
using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;

using BO = PHSRAG.Insight21.BusinessObjects;
using Utility = PHSRAG.Utility;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using DataAccess = PHSRAG.Utility.DataAccess;

#endregion

namespace PHSRAG.Insight21.FormsManagement
{
	#region Class QuestionDocument
	/// <summary>
	/// QuestionDocument specifies a type of the document (like ProtocolSummary, Schema, etc) that needs to be attached to the protocol
	/// 
	/// QuestionDocuments are tied to a QuestionnaireVersion
	/// </summary>
	public class QuestionDocument : BO.SmartBusinessObject, ICloneable
	{
		#region Constants
		private const string QuestionDocumentKey = "QuestionDocumentKey_36151A69-9C1B-4e16-9B79-74F7E7E60D0C";

		private const string ColumnId = "Id";
		private const string ColumnVersionId = "VersionId";
		private const string ColumnRequired = "Required";
		private const string ColumnType = "Type";
		private const string ColumnItemName = "ItemName";
		private const string ColumnItemValue = "ItemValue";
		private const string ColumnValidationMessage = "ValidationMessage";
		#endregion

		#region Instance Variables (private)
		private int versionId;
		private string type;
		private string validationMessage;
		private bool isRequired;
		private string itemName;
		private string itemValue;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new QuestionDocument object based on the Cache Policy passed in as a parameter. 
		/// </summary>
		/// <param name="cachePolicy">The prevalent cache policy</param>
		public QuestionDocument(ICachePolicy cachePolicy) : base(cachePolicy)
		{
		}

		/// <summary>
		/// Constructs a new QuestionDocument object based on the Cache Policy passed in as a parameter. 
		/// All the instance variables will be set to the corresponding values specified in the Data Row
		/// </summary>
		/// <param name="cachePolicy">The prevalent cache policy</param>
		/// <param name="dataRow">DataRow holding the values to be assigned to instance variables</param>
		public QuestionDocument(ICachePolicy cachePolicy, DataRow dataRow ) : base(cachePolicy)
		{
			PopulateDataMembers(dataRow);
			
		}
		#endregion

        #region ICloneable
        object ICloneable.Clone()
        {
            return Clone();
        }
        #endregion

        public QuestionDocument Clone()
        {
            QuestionDocument document = (QuestionDocument)MemberwiseClone( );
            document.Id = 0;
            document.Dirty = true;

            return document;
        }

		#region Properties
		/// <summary>
		/// Gets or sets the version id of the QuestionDocument object
		/// </summary>
		public int VersionId
		{
			get { return versionId; }
			set { SetDirty(ref versionId, value); }
		}

		
		/// <summary>
		/// Gets or sets the type of the QuestionDocument
		/// </summary>
		public string Type
		{
			get	{ return type; }
			set	{ SetDirty(ref type, value); }
		}
		

		/// <summary>
		/// Gets or sets whether or not the document is required
		/// </summary>
		public bool IsRequired
		{
			get { return isRequired; }
			set { SetDirty(ref isRequired, value); }
		}


		/// <summary>
		/// Gets or sets the validation message that is displayed if the document is required and is not attached by the user
		/// </summary>
		public string ValidationMessage
		{
			get	{ return validationMessage;	}
			set	{ SetDirty(ref validationMessage, value); }
		}
		

		/// <summary>
		/// Gets or sets the name of the QuestionnaireItem to which the QuestionDocument is tied
		/// </summary>
		public string ItemName
		{
			get { return itemName; }
			set { SetDirty(ref itemName, value); }
		}


		/// <summary>
		/// Gets or sets the value to which the QuestionnaireItem must be set for the Questiondocument to be attached by the user
		/// </summary>
		public string ItemValue
		{
			get { return itemValue; }
			set { SetDirty(ref itemValue, value); }
		}
		#endregion

		#region Caching
		/// <summary>
		/// Cache Key uniquely identifies this object within the cache.
		/// </summary>
		/// <returns>the unique string for this object.</returns>
		public override string CacheKey()
		{
			return QuestionDocumentKey;
		}

		/// <summary>
		/// Cache this instance using the prevalent cache policy.
		/// </summary>
		public override void Cache()
		{
			CachePolicy.Cache(QuestionDocumentKey, this);
		}

		/// <summary>
		/// Remove this instance from the cache using the prevalent cache policy.
		/// </summary>
		public override void UnCache()
		{
			CachePolicy.UnCache(QuestionDocumentKey);
		}
		#endregion

		#region Smart Business Object Methods

		/// <summary>
		/// Deletes the record represented by the object
		/// </summary>
		/// <param name="sqlTransaction">SQL transaction to use when deleting.</param>
		protected override void DeleteObject( SqlTransaction sqlTransaction)
		{
			try
			{
				DataAccess.ExecuteNonQuery( sqlTransaction.Connection, sqlTransaction, "DeleteQuestionDocument", 
					DataAccess.BuildSqlParameterArray(
					"@id", SqlDbType.Int, Id
					));
			}
			catch(Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog("QuestionDocument.SaveObject: Failed to save the QuestionDocument object to the database", 
																	ex, true, Utility.ExceptionReport.ReportType.Error);
				throw new Exception("QuestionDocument.SaveObject: Failed to save the QuestionDocument object to the database", ex);
			}
		}


		/// <summary>
		/// Saves the state of the QuestionDocument object to the database. 
		/// The stored procedure inserts a new record if the id of the object is 0, 
		/// otherwise the procedure updates the record with the matching questiondocument id
		/// </summary>
		/// <param name="sqlTransaction">The database context in which the underlying sql statement needs to be executed</param>
		protected override void SaveObject( SqlTransaction transaction )
		{
			try
			{
				Id = Convert.ToInt32(DataAccess.ExecuteScalar( transaction.Connection, transaction, "SaveQuestionDocument", DataAccess.BuildSqlParameterArray(
					"@id", SqlDbType.Int, Id,
					"@versionID", SqlDbType.Int, versionId,
					"@type", SqlDbType.VarChar, type,
					"@required", SqlDbType.Bit, isRequired,
					"@itemName", SqlDbType.VarChar, itemName,
					"@itemValue", SqlDbType.VarChar, itemValue,
					"@validationMessage", SqlDbType.VarChar, validationMessage
					)));
			}
			catch(Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog("QuestionDocument.SaveObject: Failed to save the QuestionDocument object to the database", 
																	ex, true, Utility.ExceptionReport.ReportType.Error);
				throw new Exception("QuestionDocument.SaveObject: Failed to save the QuestionDocument object to the database", ex);
			}
		}


		/// <summary>
		///  Loads the QuestionDocument based on the optional Args.
		/// </summary>
		/// <param name="connectionString">Information to connect to the database</param>
		/// <param name="args">QuestionDocument Id of the object to be loaded</param>
		public override void Load ( string connectionString, params object[] args )
		{
			if ( args.Length != 1 )
				throw new Exception("QuestionDocument Load expects  ID");

			try
			{
				DataSet newDataSet = new DataSet();
				Utility.DataAccess.LoadDataSet(newDataSet, "QuestionDocument", connectionString, "GetQuestionDocument", 
					Utility.DataAccess.BuildSqlParameterArray(
					"@id", SqlDbType.Int, (int)args[0]
					));
				if (newDataSet.Tables.Count > 0)
				{
					DataRowCollection rows = newDataSet.Tables["QuestionDocument"].Rows;
					if (rows.Count > 0)
					{
						PopulateDataMembers(rows[0]);
					}
					else
					{
						throw new Exception("QuestionDocument.Load: No row found with the specified id");
					}
				}
				else
				{
					throw new Exception("GetQuestionDocument stored procedure returned incorrect results");
				}
			}
			catch( Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog ("Failed to load QuestionDocument with the specified id", e, true, Utility.ExceptionReport.ReportType.Error);
				throw new Exception("Failed to load QuestionDocument with the specified id", e);
			}
			
		}
		#endregion

		#region Static Get methods
		/// <summary>
		/// 
		/// </summary>
		/// <param name="cachePolicy">The prevalent cache policy</param>
		/// <param name="versionId">The id the Questionnaire Version of which the Questionnaire Items have to be fetched</param>
		/// <returns>Returns a collection of questiondocuments</returns>
		public static ArrayList GetQuestionDocumentsForVersion (ICachePolicy cachePolicy, int versionId )
		{
			ArrayList documentsList = new ArrayList();
			try
			{
				DataSet ds = Utility.DataAccess.GetDataSet(Utility.DataAccess.GetConnectionString(), "GetQuestionDocumentsForVersion", 
					Utility.DataAccess.BuildSqlParameterArray
					("@versionId", SqlDbType.Int, versionId));
				DataRowCollection rows = ds.Tables[0].Rows;
				foreach( DataRow row in rows )
				{
					documentsList.Add (new QuestionDocument(cachePolicy, row));
				}
			}
			catch(Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog ("Failed to load Questionnaire Documents", ex, true, Utility.ExceptionReport.ReportType.Error);
				throw new Exception("Failed to load Questionnaire Documents", ex);
			}

			return documentsList;
		}
		#endregion		

		#region Private methods
		/// <summary>
		/// Populates instance fields with corresponding values in the datarow
		/// </summary>
		/// <param name="dataRow">DataRow holding the values to be assigned to instance variables</param>
		private void PopulateDataMembers(DataRow dataRow)
		{
			Id = (int)dataRow[ColumnId];
			versionId = (int)dataRow[ColumnVersionId];
			type = (string)dataRow[ColumnType];
			validationMessage = (string)dataRow[ColumnValidationMessage];
			isRequired = (bool)dataRow[ColumnRequired];
			itemName = (string)dataRow[ColumnItemName];
			itemValue = (string)dataRow[ColumnItemValue];
		}
		#endregion
	}
	#endregion
}
